home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-02
/
helpxref.zip
/
HELPXREF.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1990-11-19
|
35KB
|
1,075 lines
Program HelpXRef;
{ Released to Public Domain by David G. Cohen }
{ Compiles under Turbo 5.5 with Object Professional 1.02
untested with 1.03, likely compatible. Problems, questions, remarks,
or coded additions requested at CIS 70062,1720 or Genie D.COHEN8 }
Uses OpLArray,OpFrame,OpString,OpDos,Dos,OpCrt,
OpSort,OpWindow;
const
MyColors : ColorSet = (
TextColor : $1E; TextMono : $0F;
CtrlColor : $1E; CtrlMono : $0F;
FrameColor : $1F; FrameMono : $0F;
HeaderColor : $1F; HeaderMono : $70;
ShadowColor : $0B; ShadowMono : $0F;
HighlightColor : $4F; HighlightMono : $70;
PromptColor : $1B; PromptMono : $07;
SelPromptColor : $1F; SelPromptMono : $0F;
ProPromptColor : $1B; ProPromptMono : $07;
FieldColor : $1E; FieldMono : $0F;
SelFieldColor : $3E; SelFieldMono : $70;
ProFieldColor : $17; ProFieldMono : $07;
ScrollBarColor : $1B; ScrollBarMono : $07;
SliderColor : $1B; SliderMono : $0F;
HotSpotColor : $30; HotSpotMono : $70;
BlockColor : $3E; BlockMono : $0F;
MarkerColor : $3F; MarkerMono : $70;
DelimColor : $1E; DelimMono : $0F;
SelDelimColor : $31; SelDelimMono : $0F;
ProDelimColor : $1E; ProDelimMono : $0F;
SelItemColor : $3E; SelItemMono : $70;
ProItemColor : $17; ProItemMono : $07;
HighItemColor : $1F; HighItemMono : $0F;
AltItemColor : $1F; AltItemMono : $0F;
AltSelItemColor : $3F; AltSelItemMono : $70;
FlexAHelpColor : $1F; FlexAHelpMono : $0F;
FlexBHelpColor : $1F; FlexBHelpMono : $0F;
FlexCHelpColor : $1B; FlexCHelpMono : $70;
UnselXrefColor : $1E; UnselXrefMono : $08;
SelXrefColor : $3F; SelXrefMono : $70;
MouseColor : $4F; MouseMono : $70
);
Version = '1.06';
NotFound = $FFFF;
FunctorNotFound = #00;
Delim = '~';
Status = 2;
Result = 3; { what line in window to write on }
CurrentFile = 5;
Addition = 10;
Bright = 100;
LowTopicNumberStart = 100;
Type
CompressedStr = string[7];
IndexPtr = ^IndexRecType;
IndexRecType = record { SizeOf = 17 bytes, approx. 5880 recs/100K }
Name : CompressedStr; { Compression of indexable item name (any str) }
Volume : Byte; { Volume number of indexable item (max is 9) }
Page : Word; { Represent 'nn-nnn' as nnnnn, (max is 65-535) }
Left,
Right : IndexPtr; { Binary Tree Sibling Pointers }
end;
{ Usage Note: Once found, hi bit of volume is set to 1, so }
{ in effect, volume:=volume+128. }
FileBuffer10KType = Array[1..10240] of Char;
WhereToWrite = Integer;
DupListType = Array[1..5000] of char;
Var
AskForKey : Boolean; { True if get key when done }
BigWindow : RawWindow; { Interface window }
BytesA : word; { used by compress }
BytesB : byte;
BytesC : word;
CurrentSearch : String; { What Search proc looks for }
Debug : Boolean;
DupList : DupListType; { Holds duplicates in index }
DupListUsed : Integer;
DupTopicNumber : Word; { A known method duplicate }
ExitRequestPending : Boolean; { True of abort requested }
FileBuffer10K : FileBuffer10KType; { Buffering area }
FvDups : Text; { Duplicates file, writing }
FvLog : Text; { Log file, writing }
IndexFile : Text; { Index file, reading }
IndexFileName : String; { Second paramater, filename }
InFile : Text; { File currently reading }
LargeArr: OpArray;
Logging : Boolean; { True if /L switch used }
LowTopicNumber : Integer; { Last reserved # used }
MemMark : Pointer; { Start of heap for b-tree }
Name : CompressedStr; { A compressed string }
NumIncludes : Integer;
NumInDupList : Word;
NumInIndex : LongInt; { Items in the index file }
NumTopics : Word; { !TOPIC's read so far }
NumXRefed : Word; { Topics cross refed so far }
OutFile : Text; { File currently writing }
Page : Word; { Page number out of index }
Emulating : Boolean; { True if /Q switch used }
Root : IndexPtr; { Top of b-tree (index recs) }
StartMs : LongInt; { Start time }
TempFileName : String; { Temporary file name }
ThisInclude : String; { Name of current !INCLUDE }
Timing : Boolean; { True of /T switch used }
TopFile : Text; { Top most .txt file }
TopFileName : String; { First paramater, file name }
Topic : Word; { Current topic number }
TopicAlreadyRead : Boolean; { True of topic in var below }
TopicLinePreviouslyRead : String; { Associated with above }
Volume : Byte; { Volume from index }
WriteBuffer10K : FileBuffer10KType; { Buffering area }
WrittenDups : Word;
{ Forward references }
Procedure CloseBigWindow; Forward;
Procedure OpenBigWindow; Forward;
Procedure Say(WhatToSay: String; Where: WhereToWrite); Forward;
Procedure VerboseSyntax; Forward;
Function CompressString(S:string) : CompressedStr; Forward;
procedure FlushKey;
{- Flush the keyboard buffer }
var
Tword : word;
begin
while CheckKbd(Tword) do Tword := ReadKeyWord;
end;
Procedure Error(problem: String);
{- Report problem and halt with error }
Begin
if not Emulating then Clrscr; { really just clear bigwindow }
writeln;
WriteLn(' There was an error in processing your request.');
WriteLn;
Writeln;
WriteLn(' Cause of Termination: ',problem);
WriteLn;
WriteLn;
WriteLn(' For syntax, please type HELPXREF at the command line.');
WriteLn;
if not Emulating then CloseBigWindow;
Halt(1);
End;
Procedure SetSwitches;
{- Set optional switches, all are false on entry except AskForKey }
Var
A : Integer;
Begin
for a:=3 to ParamCount do begin
if StUpCase(ParamStr(a)) = '/L' then Logging:=True
else if StUpCase(ParamStr(a)) = '/T' then Timing:=True
else if StUpCase(ParamStr(a)) = '/E' then Emulating:=True
else if StUpCase(ParamStr(a)) = '/N' then AskForKey:=False
else if StUpCase(ParamStr(a)) = '/D' then Debug:=True
else if ParamStr(a) = '/?' then VerboseSyntax
else begin
Emulating:=True; { because window is not open yet }
Error('Invalid parameter "'+ParamStr(a)+'"');
end;
end;
End;
Procedure InitializeGlobals;
{- Initialize all global variables }
Begin
Logging:=False; Timing:=False; Emulating:=False; Debug:=False;
AskForKey:=True;
LowTopicNumber:=LowTopicNumberStart;
ExitRequestPending:=False;
Root:=Nil; NumXRefed:=0; NumTopics:=0; NumInIndex:=0;
WrittenDups:=0; DupListUsed:=0; NumInDupList:=0;
NumIncludes:=0;
TempFileName:='ADDREFS$.$$$';
TopFileName:=ParamStr(1);
End;
Procedure AssignFiles;
{- Make global file assignments }
Begin
if paramcount < 2 then Error('Files not specified.');
if not ExistFile(ParamStr(1)) then
Error('Top-most file "'+TopFileName+'" not found.');
Assign(Topfile,TopFileName);
Reset(TopFile);
Assign(OutFile,TempFileName);
Rewrite(OutFile);
IndexFileName:=ParamStr(2);
if Logging then begin
assign(FvLog,'HELPXREF.LOG');
rewrite(FvLog);
writeln(FvLog,'The following are topics which are not in the index.');
writeln(FvLog);
end;
assign(FvDups,'HELPXREF.DUP');
rewrite(FvDups);
End;
Procedure VerboseSyntax;
{- Give long syntax screen, if paramcount = 0 or /? specified, halt with error }
Begin
WriteLn;
WriteLn('HELPXREF by David G. Cohen CIS 70062,1720 -or- Genie D.COHEN8');
WriteLn;
WriteLn('HelpXRef performs three major functions which will hopefully');
WriteLn('increase the functionality of your OPRO hypertext help.');
WriteLn('1. Add page references to all methods.');
WriteLn('2. Build new topics for duplicate methods which are linked to');
WriteLn(' the objects where the methods are defined.');
WriteLn('3. Link each method which exists in more than one object with');
WriteLn(' all the other objects where the method exists.');
WriteLn;
WriteLn('Syntax: HELPXREF topfile indexfile [optional switches]');
WriteLn(' Topfile is the topmost help file which INCLUDEs others.');
WriteLn(' Indexfile is the index distributed with opro.');
WriteLn;
WriteLn(' Optional Switches: ');
WriteLn(' /D Duplicates Place duplicates in HELPXREF.DUP');
WriteLn(' /E Emulate Screen output will appear in opro''s format.');
WriteLn(' /L Log Log a summary to HELPXREF.LOG.');
WriteLn(' /N No Ask Do not ask to press a key upon completion.');
WriteLn(' /T Time Time the execution.');
Halt(1);
End;
Procedure Initialize;
{- Set up windows, globals, files, etc }
Begin
if ParamCount = 0 then VerboseSyntax;
InitializeGlobals;
SetSwitches;
FlushKey;
if not Emulating then
OpenBigWindow
else
WriteLn;
Say('Initializing.',Status);
AssignFiles;
if Timing then StartMs:=TimeMs;
End;
Procedure WriteHeaderGroup1;
{- Write headers for use in adding page references }
Begin
BigWindow.wFastWrite('Current File :',CurrentFile,2,MyColors.PromptColor);
BigWindow.wFastWrite('Indexed Item',CurrentFile+1,2,MyColors.PromptColor);
BigWindow.wFastWrite('Added Reference',CurrentFile+1,51,MyColors.PromptColor);
End;
Procedure WriteHeaderGroup2;
{- Write headers for use in adding duplicate topics }
Begin
BigWindow.wFastWrite('Current File :',CurrentFile,2,MyColors.PromptColor);
BigWindow.wFastWrite('Duplicated Method',CurrentFile+1,2,MyColors.PromptColor);
BigWindow.wFastWrite('Associated Object',CurrentFile+1,51,MyColors.PromptColor);
End;
Procedure CreateANode(var Root: IndexPtr);
{- Add a node to the tree which has current index information }
Begin
if MaxAvail >= SizeOf(IndexRecType) then
begin
New(Root);
Root^.Name := Name;
Root^.Page := Page;
Root^.Volume := Volume;
Root^.Left := Nil;
Root^.Right := Nil;
end
else
Error('Out of memory.');
End;
Procedure UpdateTree(var Root: IndexPtr);
{- Place information into tree if it's not already there }
Begin
if Root=nil then CreateANode(Root)
else
begin
if Name < Root^.Name then UpdateTree(Root^.Left)
else
begin
if Name > Root^.Name then UpdateTree(Root^.Right)
else {match found}
begin
end;
end;
end;
End;
Procedure Say(WhatToSay : String; Where : WhereToWrite);
{- Write information into the on-screen window, or to screen if Emulating }
Var FlashIt: Boolean;
Begin
FlashIt:=False;
if Where > Bright then begin
FlashIt:=True;
Where:=Where-Bright;
end;
if not Emulating then
begin
if Where = Addition then begin
ScrollWindowUp(4,12,75,15,1);
BigWindow.wFastWrite(WhatToSay,Addition,2,MyColors.TextColor);
end
else begin
if not FlashIt then
BigWindow.wFastWrite(pad(WhatToSay,45),Where,19,MyColors.TextColor)
else
BigWindow.wFastWrite(pad(WhatToSay,45),Where,19,MyColors.AltItemColor);
end
end
else
if (Where = Status) or (Where=CurrentFile) then
WriteLn(pad(WhatToSay,45));
End;
Procedure AddToDupList(Functor : string);
{- Add a method to the duplicate list, if it's not there }
Var
TempFunctor: String;
CompressedFunctor: CompressedStr;
Begin
TempFunctor:=pad(functor,8);
TempFunctor:=StUpCase(ExtractWord(1,TempFunctor,['.',' ']));
CompressedFunctor:=CompressString(TempFunctor);
CompressedFunctor:=pad(CompressedFunctor,8);
if search(DupList,DupListUsed,CompressedFunctor,
length(CompressedFunctor)) = NotFound then
begin
inc(NumInDupList);
Move(CompressedFunctor,DupList[DupListUsed],sizeof(CompressedStr));
DupListUsed:=DupListUsed+sizeof(CompressedStr);
end;
end;
Procedure ReadIndex;
{- Read the index file and store information into the tree }
var
Functor : String;
IndexEntry : String;
LastFunctor : String;
Line : String;
ObjectName : String;
Temp : String[1];
UnitName : String;
begin
Say('Scanning index file.',Status);
if not ExistFile(IndexFileName) then
Error('Index file "'+IndexFileName+'" not found.');
assign(indexfile,indexfilename);
settextbuf(indexfile,FileBuffer10K);
reset(indexfile);
Repeat
ReadLn(Indexfile,Line);
Line := trim(Line);
if Line[1] = '{' then
begin
UnitName := ExtractWord(4,Line,[' ']) ; { unit name }
LastFunctor := StUpCase(Functor);
Functor := '.' + ExtractWord(3,Line,[' ']) ; { function name }
ObjectName := '.' + ExtractWord(5,Line,[' ']); { object name }
if LastFunctor = StUpCase(Functor) then
AddToDupList(Functor);
if pos('----',ObjectName) <> 0 then ObjectName:=''; { no object }
{ initialize the compression string's length }
Name:='1234567';
Name:=CompressString(StUpCase(UnitName+Functor+ObjectName));
if not Str2Word(ExtractWord(2,Line,[' ','-']) +
ExtractWord(3,Line,[' ','-']), Page) then
Page:=0; { means to use '*NEW*' }
Temp:=ExtractWord(1,Line,[' ','{','}']);
if Length(Temp) > 1 then Error('Found volume > 9 in index.');
Volume:=ord(Temp[1])-48;
inc(NumInIndex);
UpdateTree(Root);
end;
Until eof(indexfile);
Say('There are '+Long2Str(NumInIndex)+' topics in the index.',Result);
end;
Procedure XRefMethod(Method: String; ThisObject: String);
{- If this is a duplicated method, write it to the .DUP file }
Var
CompressedMethod : CompressedStr;
TempMethod : String;
Begin
TempMethod:=pad(method,8);
TempMethod:=StUpCase(ExtractWord(1,TempMethod,['.',' ']));
CompressedMethod:=CompressString(TempMethod);
compressedmethod:=pad(compressedmethod,8);
if search(DupList,DupListUsed,CompressedMethod[1],sizeof(CompressedStr)-1)
<> NotFound then
begin
WriteLn(FvDups,StUpCase(Method),Delim,StUpCase(ThisObject),Delim,Topic);
inc(WrittenDups);
end;
End;
{- Sort get, put, compare }
{$F+}
Procedure GetStr;
Var x: Word;
Line: String[60];
Begin
for x:=1 to WrittenDups do
begin
LargeArr.RetA(x,1,Line);
if not PutElement(Line) then
writeln('no put');
end;
End;
Function LessFunc(var x,y) : Boolean;
Var
X1 : String[60] absolute x;
Y1 : String[60] absolute y;
Begin
LessFunc:= X1 < Y1;
End;
Procedure PutElem;
Var x: Word;
Line:String[60];
Begin
for x:=1 to WrittenDups do
begin
if not GetElement(Line) then
writeln('no get');
LargeArr.SetA(x,1,Line);
end;
End;
{$F-}
Procedure WriteNewHelp;
{- Writes NEWXREFS.TXT which gets included in topfile }
Var
A: Integer;
DupEntry : String[60];
WhichEntry: Word;
FvDups : Text;
CurrentMethod,
Method,
ObjectReference,
MethodTopic : String;
IssueCr : Boolean;
Begin
Say('Writing duplicate method references.',Status);
if not Emulating then WriteHeaderGroup2;
Say('"NEWXREFS.TXT"',CurrentFile);
assign(FvDups,'NEWXREFS.TXT');
if ioresult<>0 then begin
writeln('file error 1');
halt(1);
end;
settextbuf(FvDups,FileBuffer10K);
rewrite(FvDups);
WriteLn(FvDups,'; This file was created by HELPXREF.');
WriteLn(FvDups,'; It is included from your topmost file and prohibits the system');
WriteLn(FvDups,'; from assuming the object which goes with the method passed to it.');
WriteLn(FvDups,'; For instance, ''Init'' will no longer just pick the first object');
WriteLn(FvDups,'; where an init method is defined; instead, you will be presented');
WriteLn(FvDups,'; with a choice of objects all linked as required.');
WriteLn(FvDups,'; Please see the comments about biasing at the end of this file.');
WriteLn(FvDups,'; These comments may be removed if desired.');
WriteLn(FvDups);
if ioresult<>0 then begin
writeln('file error 2');
halt(1);
end;
WhichEntry:=1;
Repeat
LargeArr.RetA(WhichEntry,1,DupEntry);
CurrentMethod:=ExtractWord(1,DupEntry,[Delim]);
ObjectReference:=ExtractWord(2,DupEntry,[Delim]);
MethodTopic:=LeftPad(ExtractWord(3,DupEntry,[Delim]),5);
for a:=1 to 4 do
if MethodTopic[a]=' ' then MethodTopic[a]:='0';
WriteLn(FvDups,'!TOPIC ',LowTopicNumber,' ',CurrentMethod);
inc(LowTopicNumber);
WriteLn(FvDups,'!NOINDEX');
WriteLn(FvDups,'!BIAS ',LowTopicNumberStart+NumInDupList);
WriteLn(FvDups);
WriteLn(FvDups,'The ',CurrentMethod,' method is defined in these objects;');
WriteLn(FvDups);
Method:=CurrentMethod;
IssueCR:=True;
Repeat
Write(FvDups,pad(' '+#4+MethodTopic+#5+ObjectReference+#5,35));
IssueCR:=not IssueCR;
if IssueCr then Writeln(FvDups);
inc(WhichEntry);
if WhichEntry <= WrittenDups then
begin
Say(copy(pad(StLoCase(CurrentMethod),47)+' '+StLoCase(ObjectReference),1,72),Addition);
LargeArr.RetA(WhichEntry,1,DupEntry);
Method:=ExtractWord(1,DupEntry,[Delim]);
ObjectReference:=ExtractWord(2,DupEntry,[Delim]);
MethodTopic:=LeftPad(ExtractWord(3,DupEntry,[Delim]),5);
for a:=1 to 4 do
if MethodTopic[a]=' ' then MethodTopic[a]:='0';
end;
Until (Method<>CurrentMethod) or (WhichEntry > WrittenDups);
Writeln(FvDups);
Writeln(FvDups,'!BIAS 0');
Writeln(FvDups);
Writeln(FvDups,';----------------------------------------------------------');
WriteLn(FvDups);
Until (WhichEntry > WrittenDups);
WriteLn(FvDups,'!BIAS ',LowTopicNumberStart+NumInDupList);
WriteLn(FvDups,'; This bias is minimal and will not waste space in the resulting');
WriteLn(FvDups,'; compiled help file. It is placed here by HELPXREF to ensure that');
WriteLn(FvDups,'; the topics are not overwritten by any of the opro topics or');
WriteLn(FvDups,'; topics you may have added.');
close(FvDups);
End;
Procedure LogDups;
{- If debug is on, dump all duplicates (sorted) into HelpXRef.Dup }
Var
FvDups: Text;
Loop : Integer;
DuplicatedMethod : String;
Begin
assign(FvDups,'HELPXREF.DUP');
rewrite(FvDups);
WriteLn(FvDups,'The following are methods which exist in multiple objects.');
WriteLn(FvDups);
WriteLn(FvDups,'Object Method Topic Number');
for Loop:=1 to WrittenDups do
begin
LargeArr.RetA(Loop,1,DuplicatedMethod);
Write(FvDups,pad(ExtractWord(1,DuplicatedMethod,[Delim]),20));
Write(FvDups,pad(ExtractWord(2,DuplicatedMethod,[Delim]),30));
WriteLn(FvDups,pad(ExtractWord(3,DuplicatedMethod,[Delim]),10));
end;
close(FvDups);
End;
Procedure BuildMasterDupXRefs;
{- Build the master index of duplicate methods }
Var
Line: String[60];
a:integer;
count: word;
Begin
Say('Sorting duplicate method references.',Status);
Say(Long2Str(WrittenDups)+' of out '+Long2Str(NumXRefed)+' are duplicate methods.',Result);
if not Emulating then ScrollWindowUp(4,10,75,15,6);
count:=0;
assign(FvDups,'HELPXREF.DUP');
settextbuf(FvDups,FileBuffer10K);
reset(FvDups); {60}
LargeArr.Init(WrittenDups, 1, 60, 'HELPXREF.ARR', MaxAvail, lDeleteFile,
DefaultPriority);
While not eof(FvDups) do
begin
ReadLn(FvDups,Line);
inc(count);
LargeArr.SetA(count,1,Line);
end;
close(FvDups);
if count > 0 then
if Sort(count,60,GetStr,LessFunc,PutElem) = SortOutOfMemory then
Error('Out of memory (No room to sort).');
if not Debug then
begin
assign(FvDups,'HELPXREF.DUP');
erase(FvDups);
end
else
LogDups;
WriteNewHelp;
End;
Function NextTopic: String;
{- Find the next topic sequentially (From current !INCLUDE) }
Var
Line : String;
Functor : String;
Begin
if TopicAlreadyRead then
Line:=TopicLinePreviouslyRead
else
begin
Line:='';
while (pos('!TOPIC',Line) <> 1) and (not eof (infile)) do begin
ReadLn(InFile,Line);
WriteLn(OutFile,Line);
End;
End;
if eof(infile) then
Functor:=FunctorNotFound
else begin { Line contains the !TOPIC }
Functor := ExtractWord(3,Line,[' ']);
if not Str2Word(ExtractWord(2,Line,[' ']),topic) then
NumTopics:=NumTopics-1;
inc(NumTopics);
end;
NextTopic:=Functor;
End;
Function SearchTreeFor(Var Root:IndexPtr; Target:CompressedStr): IndexPtr;
{- Find target in the tree starting at the root }
begin
if Root=Nil then SearchTreeFor:=nil
else
begin
if Target < Root^.Name then SearchTreeFor:=SearchTreeFor(Root^.Left,Target)
else
begin
if Target > Root^.Name then SearchTreeFor:=SearchTreeFor(Root^.Right,Target)
else {match found}
begin
SearchTreeFor:=Root;
end;
end;
end;
End;
Procedure PayAttentionToUser;
{- User has pressed a key, user may wish to abort }
Var ch: char;
Begin
ch:=ReadKey;
if ch=#0 then ch:=ReadKey;
Say('Process suspended.',Status);
Say('Press [A] to Abort, any other key to resume.',Result);
ch:=ReadKey;
Say('Inserting page references.',Status);
if UpCase(ch)='A' then begin
ExitRequestPending:=True;
Say('Request to abort pending!',Bright+Result);
end
else
Say('There are '+Long2Str(NumInIndex)+' topics in the index.',Result);
End;
Procedure FindIndexReference;
{- See if there's an entry in the index for current topic }
Var
Line : String;
Done : Boolean;
ThisProc,
CompressedCurrent : CompressedStr;
PageRef : String;
LastLine : String;
ObjectName : String;
Node : IndexPtr;
WhatToSay,
PageStr : String;
DuplicateRef : String;
Begin
ObjectName:='';
CompressedCurrent:='1234567';
CompressedCurrent:=CompressString(CurrentSearch);
Node:=SearchTreeFor(Root,CompressedCurrent);
TopicAlreadyRead:=False;
while (Line[1]<>#2) and (not eof (infile)) and (not TopicAlreadyRead) do
begin
ReadLn(InFile,Line);
if (pos('!TOPIC',Line)) = 1 then begin
TopicAlreadyRead:=True;
WriteLn(OutFile,Line);
TopicLinePreviouslyRead:=Line;
Exit;
end;
WriteLn(OutFile,Line);
end;
ObjectName:=ExtractWord(2,Line,[#5]); { get object }
if Node = Nil then begin
CurrentSearch:=StUpCase(CurrentSearch+'.'+ObjectName);
CompressedCurrent:=CompressString(CurrentSearch);
Node:=SearchTreeFor(Root,CompressedCurrent);
if Logging then
if Node = Nil then
WriteLn(FvLog,CurrentSearch);
end;
if Node <> Nil then begin
if Node^.Volume > 9 then
Node^.Volume:=Node^.Volume-128; { Temporarily mark as unused }
ThisProc:=Node^.Name;
PageStr:=Long2Str(Node^.Page);
insert('-',PageStr,Length(PageStr)-2);
WhatToSay:=StLoCase(ExtractWord(2,CurrentSearch,['.']));
{ WhatToSay is the method name, do some cross referencing }
XRefMethod(WhatToSay,ObjectName);
If ObjectName <> '' then
WhatToSay:=ObjectName+'.'+WhatToSay;
if PageStr='-0' then begin
PageRef:='Text Reference: '+#2+
'This item is newer than the manuals. Check update listing'+#2;
Say(pad(WhatToSay,47)+' '+'Check update listing',Addition);
end
else begin
PageRef:='Text Reference: '+#2+'Volume ' + Long2Str(Node^.Volume) +
', page ' + PageStr+#2;
Say(pad(WhatToSay,47) + ' ' +
copy(PageRef,18,Length(PageRef)-18),Addition);
end;
Node^.Volume:=Node^.Volume + 128; { mark as used, see type defn. }
inc(NumXRefed);
Done:=FALSE;
if not eof(Infile) then
Repeat
ReadLn(Infile,Line);
if (pos('Text Reference: '+#2,Line)) <> 1 then begin
if (pos(';',Line)=1) then begin
if Length(LastLine) > 0 then
WriteLn(OutFile); { ensure 1 blank line only }
WriteLn(OutFile,PageRef);
Done:=TRUE;
end;
WriteLn(OutFile,Line);
LastLine:=Line;
end;
Until Done or (eof(InFile));
if not done then begin { reached eof before writing reference }
WriteLn(OutFile);
WriteLn(OutFile,PageRef);
end;
end
End;
Procedure OpenBigWindow;
{- Initialize output window }
Begin
BigWindow.InitCustom(4,6,76,16,MyColors,wbordered);
BigWindow.enableexplosions(8);
BigWindow.wFrame.AddShadow(shBR,shSeeThru);
BigWindow.wFrame.AddHeader(' HelpXRef ',HeTC);
BigWindow.wFrame.AddHeader(' Version '+Version+' ══',HeBR);
BigWindow.draw;
BigWindow.wFastWrite('Current Action :',Status,2,MyColors.PromptColor);
BigWindow.wFastWrite('Status Remark :',Result,2,MyColors.PromptColor);
End;
Procedure SaySuccess;
{ Give success message if applicable }
Var Seconds,Minutes: Longint;
Begin
WriteLn;
if ExitRequestPending then begin
WriteLn(' The process was aborted.');
WriteLn;
WriteLn(' Topics in Index File : ',NumInIndex);
WriteLn(' Topics Cross Referenced : ',NumXRefed,' (prior to abort)');
WriteLn;
if Logging then
WriteLn(' Request to log results was not processed.');
if Timing then
WriteLn(' Request to time execution was not processed.');
end
else { user did not abort }
begin
if NumXRefed = 0 then begin
WriteLn(' No topics were cross referenced.');
WriteLn;
WriteLn(' Check: ');
WriteLn(' 1) Specification of files');
WriteLn(' 2) Structure of the index file');
WriteLn(' 3) Documentation');
end
else begin
Write(' Cross referencing completed successfully');
if Timing then begin
Seconds:=(TimeMs-StartMs) div 1000;
Minutes:=Seconds div 60;
Seconds:=Seconds - Minutes * 60;
Write(' in ',Minutes,' min, ',Seconds,' sec');
end;
if Logging then Write(', log created');
WriteLn('.');
WriteLn;
WriteLn(' Topics in Index File : ',NumInIndex);
WriteLn(' Total !TOPICs Found : ',NumTopics);
WriteLn(' Topics Cross Referenced : ',NumXRefed);
WriteLn(' Duplicate Methods Found : ',LowTopicNumber-LowTopicNumberStart);
end;
end;
WriteLn;
End;
Procedure CloseBigWindow;
{ Close the output window }
Var
a:char;
Begin
if AskForKey then begin
Write(' Please press a key. ');
a:=ReadKey;
end;
BigWindow.Erase;
BigWindow.Done;
End;
Procedure DoThisInclude;
{ Process the next include (ThisInclude) }
Var
Functor: String;
Begin
assign(InFile,ThisInclude);
SetTextBuf(InFile,FileBuffer10K);
reset(InFile);
Say(ThisInclude,CurrentFile);
if not Emulating then ScrollWindowUp(4,12,75,15,4);
while not eof(InFile) do begin
Functor:=NextTopic;
if KeyPressed then PayAttentionToUser;
CurrentSearch:=StUpCase(JustName(ThisInclude)+'.'+Functor);
if Functor <> FunctorNotFound then FindIndexReference;
end;
close(infile);
erase(infile);
close(outfile);
rename(outfile,ThisInclude);
assign(outfile,TempFileName);
settextbuf(outfile,WriteBuffer10K);
rewrite(outfile);
End;
Procedure AlterTopFile;
{- Alter Topmost file to include NEWXREFS.TXT }
Var
AddedFlag:Boolean;
Line: String;
Begin
Assign(InFile,TopFileName);
reset(InFile);
Assign(OutFile,'HELPXREF.$$$');
rewrite(OutFile);
AddedFlag:=False;
while not eof(InFile) do
begin
ReadLn(InFile,Line);
if (not AddedFlag) and (StUpCase(ExtractWord(1,Line,[' '])) = '!INCLUDE') then
begin
if ExtractWord(2,Line,[' ']) <> 'NEWXREFS.TXT' then
begin
WriteLn(OutFile,'!INCLUDE NEWXREFS.TXT');
WriteLn(OutFile,'; The preceeding line was generated by HelpXRef. ');
WriteLn(OutFile,'; This include must come BEFORE all other includes.');
WriteLn(OutFile,';');
end;
AddedFlag:=TRUE;
end;
WriteLn(OutFile,Line);
end;
close(InFile);
erase(InFile);
close(OutFile);
assign(OutFile,'HELPXREF.$$$');
rename(OutFile,TopFileName);
End;
Procedure Process;
{- Process the topmost file }
Var
Line:String;
Begin
Mark(memmark);
ReadIndex;
if not Emulating then WriteHeaderGroup1;
Say('Inserting page references.',Status);
Repeat
ReadLn(TopFile,Line);
if pos('!INCLUDE',StUpCase(Line)) = 1 then begin
ThisInclude:=ExtractWord(2,Line,[' ']);
if StUpCase(ThisInclude) <> 'NEWXREFS.TXT' then
begin
inc(NumIncludes);
if not ExistFile(ThisInclude) then
Error('Can''t include '+ThisInclude+', not found.');
DoThisInclude;
if ExitRequestPending then Exit;
end;
End;
Until eof(TopFile);
close(FvDups);
release(memmark);
if WrittenDups > 0 then
begin
BuildMasterDupXRefs;
AlterTopFile;
end;
End;
Procedure LogIndexNotUsed(Root: IndexPtr);
{- if logging, write parts of index not used }
Var
Line: String;
UnitName,
Functor,
ObjectName: String;
Name: CompressedStr;
Node: IndexPtr;
Begin
Say('Logging to HELPXREF.LOG.',Status);
Say('Cross referenced '+Long2Str(NumXRefed)+' topics.',Result);
if not Emulating then ScrollWindowUp(4,10,76,15,6);
WriteLn(FvLog);
WriteLn(FvLog,'The following are items in the index for which a topic was not found.');
Writeln(FvLog);
assign(indexfile,indexfilename);
settextbuf(indexfile,FileBuffer10K);
reset(indexfile);
Repeat
ReadLn(Indexfile,Line);
Line := trim(Line);
if Line[1] = '{' then
begin
UnitName := ExtractWord(4,Line,[' ']) ; { unit name }
Functor := '.' + ExtractWord(3,Line,[' ']) ; { function name }
ObjectName := '.' + ExtractWord(5,Line,[' ']); { object name }
if pos('----',ObjectName) <> 0 then ObjectName:='';
Name:='1234567'; { initialize compression string }
Name:=CompressString(StUpCase(UnitName+Functor+ObjectName));
Node:=SearchTreeFor(Root,Name);
if Node^.Volume < 10 then
if UnitName <> '' then begin
if Length(ObjectName) = 0 then
Write(FvLog,pad(copy(Functor,2,length(Functor)),40))
else
Write(FvLog,pad(copy(ObjectName,2,length(ObjectName))+
Functor,40));
WriteLn(FvLog,' ('+UnitName+')');
end;
end;
Until eof(indexfile);
close(IndexFile);
End;
Procedure LogVars;
{- Write stats }
Begin
Writeln(FvLog);
Writeln(FvLog,'Summary:');
Writeln(FvLog);
Writeln(FvLog,'!INCLUDE directives : ',NumIncludes);
Writeln(FvLog,'!TOPIC directives : ',NumTopics);
Writeln(FvLog,'Items found in index file : ',NumInIndex);
Writeln(FvLog,'Index entrys with no !TOPIC : ',NumInIndex-NumXRefed);
Writeln(FvLog,'Page references added : ',NumXRefed);
Writeln(FvLog,'Duplicate method topics added : ',LowTopicNumber-LowTopicNumberStart);
Writeln(FvLog,'References to above added : ',WrittenDups);
Writeln(FvLog,'Total new cross references : ',LowTopicNumber-LowTopicNumberStart+
NumXRefed+WrittenDups);
WriteLn(FvLog);
End;
Procedure WrapUp;
{- Tidy up }
Var a:char;
FvDel: Text;
Begin
if Logging then begin
if not ExitRequestPending then
begin
LogIndexNotUsed(Root);
LogVars;
end;
close(FvLog);
end;
if not Emulating then ClrScr;
SaySuccess;
if not Emulating then CloseBigWindow;
if ExistFile('ADDREFS$.$$$') then
begin
assign(FvDel,'ADDREFS$.$$$');
erase(FvDel);
end;
End;
{ Thanks to Major Robert W. Reed for CompressString, public domain }
{- Return a statistically unique eight byte code }
function CompressString(S:string) : CompressedStr;
var
i : byte;
T : CompressedStr;
begin
{ compress if original string is longer than compressed string }
if length(S) > 7 then
begin
{ initialize vars }
BytesA := ord(S[2]);
BytesC := ord(S[3]);
BytesB := ord(S[length(S)]);
{ perform the numeric compressions }
for i := 1 to length(S) do
begin
BytesA := BytesA XOR (ord(S[i]) * i);
BytesB := BytesB XOR (ord(S[i]) * i);
BytesC := (BytesA + BytesB) * i;
end;
{ store the results in the output string }
T := '1234567';
T[1] := S[0];
T[2] := S[1];
T[3] := chr(lo(BytesA));
T[4] := chr(hi(BytesA));
T[5] := chr(BytesB);
T[6] := chr(lo(BytesC));
T[7] := chr(hi(BytesC));
end
else T := S; { simply store the original string to return }
CompressString := T;
end;
Begin
Initialize;
Process;
WrapUp;
End.